from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from view import  Ui_login,Ui_view_up_down,Ui_login_fail,Ui_Register_view,Ui_Register_Fail,Ui_catalog
from view import  Ui_download_success,Ui_upload,Ui_upload_success
import  sys
from client import Client
import time,os,json,struct,config,logging
from config import  packet_attr,packet_type

logger = logging.getLogger(__name__)
logger.setLevel(level=logging.DEBUG)
file_handler = logging.FileHandler('client.log')
file_handler.setLevel(level = logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)

client = Client('127.0.0.1',6969)
#登陆界面
class MyWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super(QtWidgets.QMainWindow,self).__init__()
        self.ui = Ui_login.Ui_MainWindow()
        self.ui.setupUi(self)
    #槽函数
    def on_login(self):
        username = self.ui.plainTextEdit.toPlainText()
        password = self.ui.plainTextEdit_2.toPlainText()
        if client.login(username,password):
            window.close()
            dialog.show()
        else:
            window.close()
            fail_dialog.show()
    
    def on_register(self):
        window.close()
        register_dialog.show()
                    

#下载文件和上传文件的选择界面，登陆成功后出现
class MyDialog(QtWidgets.QDialog):
    def __init__(self):
        super(QtWidgets.QDialog,self).__init__()
        self.ui = Ui_view_up_down.Ui_Dialog()
        self.ui.setupUi(self)
    
    def on_push_download(self):
        dialog.close()
        list = client.showCatalog()
        print(list)
        catalog_dialog.ui.listWidget.clear()
        for item in list:
            catalog_dialog.ui.listWidget.addItem(item)
        catalog_dialog.show()
    
    def on_push_upload(self):
        dialog.close()
        upload_view.show()

    def on_push_return(self):
        dialog.close()
        window.show()


#登陆失败时的显示界面
class FailDialog(QtWidgets.QDialog):
    def __init__(self):
        super(QtWidgets.QDialog,self).__init__()
        self.ui = Ui_login_fail.Ui_Dialog2()
        self.ui.setupUi(self)
    
    def on_return(self):
        fail_dialog.close()
        window.show()

#用户注册界面
class  RegisterDialog(QtWidgets.QDialog):
    def __init__(self):
        super(QtWidgets.QDialog,self).__init__()
        self.ui = Ui_Register_view.Ui_Dialog_Register()
        self.ui.setupUi(self)

    #点击确定按钮 槽函数
    def on_click_confirm(self):
        user_name =  self.ui.textEdit.toPlainText()
        password = self.ui.textEdit_2.toPlainText()
        if client.register(user_name,password):
            register_dialog.close()
            window.show()
        else:
            register_dialog.close()
            register_fail_dialog.show()

    def on_return(self):
        register_dialog.close()
        window.show()

#注册失败的界面
class  RegisterFailDialog(QtWidgets.QDialog):
    def __init__(self):
        super(QtWidgets.QDialog,self).__init__()
        self.ui = Ui_Register_Fail.Ui_Dialog_Register_Fail()
        self.ui.setupUi(self)
    
    def on_return(self):
        register_fail_dialog.close()
        register_dialog.show()

#下载成功时的显示界面
class ViewSuccess(QtWidgets.QDialog):
    def __init__(self):
        super(QtWidgets.QDialog,self).__init__()
        self.ui = Ui_download_success.Ui_Dialog_Catalog()
        self.ui.setupUi(self)

    def on_push_return(self):
        success_view.close()
        dialog.show()

#目录界面，登陆成功后选择下载文件时显示
class CatalogDialog(QtWidgets.QDialog):
    def __init__(self):
        super(QtWidgets.QDialog,self).__init__()
        self.ui = Ui_catalog.Ui_Dialog_Catalog()
        self.ui.setupUi(self)
    
    def on_push_download(self):
        filename = self.ui.listWidget.currentItem().text()
        print(filename)
        print(type(filename))
        if client.download(filename):
            catalog_dialog.close()
            success_view.show()
    
    def on_push_return(self):
        catalog_dialog.close()
        dialog.show()

#上传文件界面
class  UploadDialog(QtWidgets.QDialog):
    def __init__(self):
        super(QtWidgets.QDialog,self).__init__()
        self.ui = Ui_upload.Ui_Dialog_Upload()
        self.ui.setupUi(self)
    

    def on_push_upload(self):
        self.uploadthread = UPloadThread()
        self.barthread = BarThread()
        self.uploadthread.signal.connect(self.change_view)
        self.barthread.signal.connect(self.setValue)
        self.uploadthread.start()
        self.barthread.start()

    
    def on_push_return(self):
        upload_view.close()
        dialog.show()
    
    def change_view(self):
        upload_view.close()
        upload_view_success.open()

    def setValue(self,value):
        self.ui.progressBar.setValue(value)
  


#上传成功后的界面
class UploadSuccessDialog(QtWidgets.QDialog):
    def __init__(self):
        super(QtWidgets.QDialog,self).__init__()
        self.ui = Ui_upload_success.Ui_Dialog_UploadSuccess()
        self.ui.setupUi(self)
    
    def on_push_return(self):
        upload_view_success.close()
        upload_view.show()



class BarThread(QtCore.QThread):
    signal = QtCore.pyqtSignal(int)
    
    def __init__(self):
        super(BarThread,self).__init__()

    def run(self):
        for i in range(101):
            time.sleep(0.2)
            self.signal.emit(i)

#上传文件线程
class UPloadThread(QtCore.QThread):
    signal = QtCore.pyqtSignal()

    def __init__(self):
        super(UPloadThread,self).__init__()

    def run(self):
        file_path = upload_view.ui.lineEdit.text()

        #获取文件大小
        file_size = os.stat(file_path).st_size

        #获取文件名称
        file_name = file_path.split('/')[-1]

        user_name = client.username
        body = bytes(json.dumps(dict(filename = file_name,filesize = file_size,username = user_name)).encode('utf-8'))
        header = struct.pack("!2I",packet_type.FILE_METADATA,len(body))
        meta_data_packet = header + body

        #发送元数据报文，通知服务器要上传文件
        client.client.send(meta_data_packet)
        logger.info('用户:'+user_name+',请求上传文件:'+ file_name)
        
        recv_header = client.client.recv(packet_attr.header_size)
        if recv_header:
            #解析返回的报头
            pkt_type,body_size = struct.unpack('!2I',recv_header)
            assert(pkt_type == packet_type.UPLOAD_RESPONSE)
            info_raw = client.client.recv(body_size)
            info_json = json.loads(info_raw)
            info = info_json['info']

            has_sent = 0
            #如果没有重名项目
            if info == 'OK!':
                #开始上传文件
                print("上传文件:"+ file_path)
                f = open(file_path,'rb')
                while True:
                    file_data = f.read(packet_attr.max_body_size)
                    header = struct.pack('!2I',packet_type.FILE_CONTENT,len(file_data))

                    if not file_data:
                        logger.info('文件上传完成！')
                        break
                    data_packet = header + file_data
                    client.client.send(data_packet)
                    has_sent += len(file_data)
                f.close()
                
            #如果服务器端存在重名文件
            elif info == "path already exsits!":
                #已经上传的文件大小
                has_sent = info_json['current_size']

                file_obj = open(file_path, 'rb')  #对文件进行读操作
                file_obj.seek(has_sent)  #调整指针

                while True:
                    data = file_obj.read(packet_attr.max_body_size)
                    header = struct.pack('!2I',packet_type.FILE_CONTENT,len(data))
                    if not data:
                        break

                    packet = header + data
                    client.client.send(packet)
                    has_sent += len(data)

                file_obj.close()
                self.exit(0)

            if has_sent == file_size:
                self.signal.emit()
                



if __name__ == '__main__':
    myapp = QtWidgets.QApplication(sys.argv)
    window = MyWindow()
    dialog = MyDialog()
    fail_dialog = FailDialog()
    register_dialog = RegisterDialog()
    register_fail_dialog = RegisterFailDialog()
    catalog_dialog = CatalogDialog()
    success_view = ViewSuccess()
    upload_view = UploadDialog()
    upload_view_success = UploadSuccessDialog()

    window.show()
    sys.exit(myapp.exec_())
    